package com.biz.primus.ms.promotion.service.feign;

import com.biz.primus.base.exception.utils.AssertUtils;
import com.biz.primus.base.vo.promotion.PromotionProductVo;
import com.biz.primus.model.promotion.exception.PromotionExceptionType;
import com.biz.primus.model.promotion.vo.PresellProductVo;
import com.biz.primus.model.promotion.vo.SeckillProductVo;
import com.biz.primus.model.promotion.vo.SpecialOfferProductVo;
import com.biz.primus.ms.promotion.dao.po.SpecialOfferPromotion;
import com.biz.primus.ms.promotion.dao.po.SpecialOfferPromotionProduct;
import com.biz.primus.ms.promotion.dao.po.UserFirstOrderCutPromotion;
import com.biz.primus.ms.promotion.dao.redis.PresellProductRedisDao;
import com.biz.primus.ms.promotion.dao.redis.SeckillProductRedisDao;
import com.biz.primus.ms.promotion.dao.ro.PresellProductRo;
import com.biz.primus.ms.promotion.dao.ro.SeckillProductRo;
import com.biz.primus.ms.promotion.feign.ProductFeignClient;
import com.biz.primus.ms.promotion.trans.SpecialOfferPromotionProductPo2VoMapper;
import com.biz.primus.product.vo.SecProductInfoReqVo;
import com.biz.primus.product.vo.SecProductInfoRespVo;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 商品Feign Service
 *
 * @author david-liu
 */
@Service
public class ProductFeignService {

    @Autowired(required = false)
    private ProductFeignClient productFeignClient;

    @Autowired
    private SeckillProductRedisDao seckillProductRedisDao;

    @Autowired
    private PresellProductRedisDao presellProductRedisDao;

    public Map<Long, List<SeckillProductVo>> getSeckillPromotionProducts(Map<Long, List<Long>> promotionProductIds) {
        if (MapUtils.isEmpty(promotionProductIds)) {
            return Collections.emptyMap();
        }

        List<Integer> entryValueSizes = Lists.newArrayList();
        List<Long> allProductIds = Lists.newArrayList();
        for (Map.Entry<Long, List<Long>> entry : promotionProductIds.entrySet()) {
            entryValueSizes.add(entry.getValue().size());
            allProductIds.addAll(entry.getValue());
        }
        List<SecProductInfoRespVo> respVos = productFeignClient.secProductInfo(new SecProductInfoReqVo(allProductIds, Lists.newArrayList()));
        if (CollectionUtils.isEmpty(respVos)) {
            return Collections.emptyMap();
        }
        Iterator<Integer> itr = entryValueSizes.iterator();
        Iterator<Long> promotionItr = promotionProductIds.keySet().iterator();
        Integer startIndex = 0;
        Map<Long, List<SeckillProductVo>> ret = Maps.newLinkedHashMap();
        Map<Long, List<SeckillProductRo>> seckillProductRos = seckillProductRedisDao.getSeckillProductRos(promotionProductIds);
        while (itr.hasNext()) {
            Integer size = itr.next();
            Long promotionId = promotionItr.next();
            List<SecProductInfoRespVo> productInfoRespVos = respVos.subList(startIndex, startIndex + size);
            List<SeckillProductRo> ros = seckillProductRos.get(promotionId).subList(startIndex, startIndex + size);
            List<SeckillProductVo> seckillProductVos = Lists.newArrayList();
            for (int i = 0; i < productInfoRespVos.size(); i++) {
                SeckillProductRo ro = ros.get(i);
                seckillProductVos.add(new SeckillProductVo(productInfoRespVos.get(i), Objects.nonNull(ro) ? ro.getRemainQuantity() : 0, Objects.nonNull(ro) ? ro.getSeckillPrice() : 0));
            }
            ret.put(promotionId, seckillProductVos);
        }
        return ret;
    }

    public Map<Long, List<PresellProductVo>> getPresellPromotionProducts(Map<Long, List<Long>> promotionProductIds) {
        if (MapUtils.isEmpty(promotionProductIds)) {
            return Collections.emptyMap();
        }

        List<Integer> entryValueSizes = Lists.newArrayList();
        List<Long> allProductIds = Lists.newArrayList();
        for (Map.Entry<Long, List<Long>> entry : promotionProductIds.entrySet()) {
            entryValueSizes.add(entry.getValue().size());
            allProductIds.addAll(entry.getValue());
        }
        List<SecProductInfoRespVo> respVos = productFeignClient.secProductInfo(new SecProductInfoReqVo(allProductIds, Lists.newArrayList()));
        if (CollectionUtils.isEmpty(respVos)) {
            return Collections.emptyMap();
        }
        Iterator<Integer> itr = entryValueSizes.iterator();
        Iterator<Long> promotionItr = promotionProductIds.keySet().iterator();
        Integer startIndex = 0;
        Map<Long, List<PresellProductVo>> ret = Maps.newLinkedHashMap();
        Map<Long, List<PresellProductRo>> seckillProductRos = presellProductRedisDao.getPresellProductRos(promotionProductIds);
        while (itr.hasNext()) {
            Integer size = itr.next();
            Long promotionId = promotionItr.next();
            List<SecProductInfoRespVo> productInfoRespVos = respVos.subList(startIndex, startIndex + size);
            List<PresellProductRo> ros = seckillProductRos.get(promotionId).subList(startIndex, startIndex + size);
            List<PresellProductVo> seckillProductVos = Lists.newArrayList();
            for (int i = 0; i < productInfoRespVos.size(); i++) {
                PresellProductRo ro = ros.get(i);
                seckillProductVos.add(new PresellProductVo(productInfoRespVos.get(i), Objects.nonNull(ro) ? ro.getRemainQuantity() : 0, Objects.nonNull(ro) ? ro.getPresellPrice() : 0, ro.getParticipateMemberCount()));
            }
            ret.put(promotionId, seckillProductVos);
        }
        return ret;
    }

    public List<SpecialOfferProductVo> getSpecialOfferProducts(SpecialOfferPromotion specialOfferPromotion) {
        if (Objects.isNull(specialOfferPromotion)) {
            return Collections.emptyList();
        }
        List<SpecialOfferPromotionProduct> promotionProducts = specialOfferPromotion.getPromotionProducts();
        if (CollectionUtils.isEmpty(promotionProducts)) {
            return Collections.emptyList();
        }
        List<Long> productIds = promotionProducts.stream().map(SpecialOfferPromotionProduct::getProductId).collect(Collectors.toList());
        List<PromotionProductVo> promotionProductVoList = productFeignClient.getPromotionProducts(productIds);
        if (CollectionUtils.isEmpty(promotionProductVoList)) {
            return Collections.emptyList();
        }
        Map<Long, PromotionProductVo> productVoMap = promotionProductVoList.stream().collect(Collectors.toMap(PromotionProductVo::getProductId, Function.identity()));
        SpecialOfferPromotionProductPo2VoMapper mapper = new SpecialOfferPromotionProductPo2VoMapper();
        return mapper.mapWithList(specialOfferPromotion.getPromotionProducts(), productVoMap);
    }

    public Map<Long, List<SpecialOfferProductVo>> getSpecialOfferProducts(List<SpecialOfferPromotion> specialOfferPromotions) {
        if (CollectionUtils.isEmpty(specialOfferPromotions)) {
            return Collections.emptyMap();
        }
        Map<Long, List<SpecialOfferProductVo>> ret = Maps.newHashMap();
        for (SpecialOfferPromotion specialOfferPromotion : specialOfferPromotions) {
            ret.put(specialOfferPromotion.getId(), this.getSpecialOfferProducts(specialOfferPromotion));
        }
        return ret;
    }

    public List<PromotionProductVo> getUserFirstOrderPromotionExcludeProducts(UserFirstOrderCutPromotion userFirstOrderCutPromotion) {
        if (Objects.isNull(userFirstOrderCutPromotion)) {
            return Collections.emptyList();
        }
        List<Long> excludeProductIds = userFirstOrderCutPromotion.getExcludeProductIds();
        if (CollectionUtils.isEmpty(excludeProductIds)) {
            return Collections.emptyList();
        }
        List<PromotionProductVo> promotionProducts = productFeignClient.getPromotionProducts(excludeProductIds);
        AssertUtils.notEmpty(promotionProducts, PromotionExceptionType.INTERNAL_SERVICE_INTERRUPT);
        return promotionProducts;
    }

    public Map<Long, List<PromotionProductVo>> getUserFirstOrderPromotionExcludeProducts(List<UserFirstOrderCutPromotion> userFirstOrderCutPromotions) {
        if (CollectionUtils.isEmpty(userFirstOrderCutPromotions)) {
            return Collections.emptyMap();
        }
        Map<Long, List<PromotionProductVo>> ret = Maps.newHashMap();
        for (UserFirstOrderCutPromotion userFirstOrderCutPromotion : userFirstOrderCutPromotions) {
            ret.put(userFirstOrderCutPromotion.getId(), this.getUserFirstOrderPromotionExcludeProducts(userFirstOrderCutPromotion));
        }
        return ret;
    }

    public SecProductInfoRespVo secProductInfo(Long productId) {
        return productFeignClient.secProductInfo(productId);
    }
}
